#pragma once

#include <map>

#include "Globals.h"
#include "Component.h"

namespace game_engine
{

typedef enum 
{
    TERRAIN_LEVEL = 0,
    ENTITY_LEVEL = 1,
    POST_PROCESS_LEVEL = 2,
    HUD_LEVEL = 3
} DrawLevelType;

// Forward declaration
class Scene;

/*!
 * \class GameObject
 * \brief 
 */
class GameObject
{
///////////////////////////////////////////////////////////////////////////////
// Attribute definition
///////////////////////////////////////////////////////////////////////////////
protected:
    string name;
    string tag;
    DrawLevelType drawLevel;
    GameObject *parent;
    Scene *scene;
    map<string, GameObject*> children;
    // FIXME : use a multimap for components!!
    map<string, Component*> components;

///////////////////////////////////////////////////////////////////////////////
// Method definition
///////////////////////////////////////////////////////////////////////////////
public:
    // Constructors and Destructors
    GameObject(void);
    GameObject(Scene *scn, const string &n, const string &t, const DrawLevelType d);
    virtual ~GameObject(void);

    // Others
    void addChild(GameObject *newChild) throw(...);
    void addComponent(Component *comp) throw(...);
    void removeComponent(const string &compType) throw(...);
    const BOOL operator<(const GameObject &other) const;
    const BOOL hasComponent(const string &compType);

    virtual void initialize(void);
    virtual void update(const FLOAT32 time);
    virtual void render(void);
    virtual void finalize(void);

    // Getters
    const string& getName(void) const;
    const string& getTag(void) const;
    const DrawLevelType getDrawLevel(void) const;
    GameObject* getParent(void) const;
    GameObject* getChild(const string &childName) const throw(...);
    Component* getComponent(const string &compType) const throw(...);
    Scene* getScene(void) const;

    // Setters
    void setName(const string &n);
    void setTag(const string &t);
    void setDrawLevel(const DrawLevelType level);
    void setParent(GameObject *p);
    void setScene(Scene *s);

private:
    const BOOL findChild(const string &childName, 
        map<string, GameObject*>::const_iterator &it) const;
    const BOOL findComponent(const string &compType, 
        map<string, Component*>::const_iterator &it) const;

};

}

